<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="####1. Spring+ActiveMQ ######1). 导包  Spring包：spring-aop-5.0.5.RELEASE.jar、spring-context-5.0.5.RELEASE.jar、spring-core-5.0.5.RELEASE.jar ActiveMQ包：activemq-all-5.15.3.jar commons: commons-pool2-2.5.0.">
<meta name="keywords" content="Android、iOS、Web、React Native">
<meta property="og:type" content="article">
<meta property="og:title" content="分布式--ActiveMQ-消息中间件(二)">
<meta property="og:url" content="http://yoursite.com/blog/2018/08/06/Distributed/分布式--ActiveMQ-消息中间件(二)/index.html">
<meta property="og:site_name" content="凌浩雨_博客">
<meta property="og:description" content="####1. Spring+ActiveMQ ######1). 导包  Spring包：spring-aop-5.0.5.RELEASE.jar、spring-context-5.0.5.RELEASE.jar、spring-core-5.0.5.RELEASE.jar ActiveMQ包：activemq-all-5.15.3.jar commons: commons-pool2-2.5.0.">
<meta property="og:locale" content="default">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-5db3fae9c0723c46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-42801b74593a4b2d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-9b7202609da8c3d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-3d4a702aac1a8965.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-f2bac201c5845ca5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-22dc6736335faa3e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-08-06T11:06:13.835Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="分布式--ActiveMQ-消息中间件(二)">
<meta name="twitter:description" content="####1. Spring+ActiveMQ ######1). 导包  Spring包：spring-aop-5.0.5.RELEASE.jar、spring-context-5.0.5.RELEASE.jar、spring-core-5.0.5.RELEASE.jar ActiveMQ包：activemq-all-5.15.3.jar commons: commons-pool2-2.5.0.">
<meta name="twitter:image" content="https://upload-images.jianshu.io/upload_images/3110861-5db3fae9c0723c46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/blog/2018/08/06/Distributed/分布式--ActiveMQ-消息中间件(二)/"/>





  <title>分布式--ActiveMQ-消息中间件(二) | 凌浩雨_博客</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">凌浩雨_博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/blog/blog/2018/08/06/Distributed/分布式--ActiveMQ-消息中间件(二)/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="凌浩雨">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpeg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="凌浩雨_博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">分布式--ActiveMQ-消息中间件(二)</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-08-06T18:01:38+08:00">
                2018-08-06
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>####1. Spring+ActiveMQ</p>
<p>######1). 导包</p>
<ul>
<li>Spring包：spring-aop-5.0.5.RELEASE.jar、spring-context-5.0.5.RELEASE.jar、spring-core-5.0.5.RELEASE.jar</li>
<li>ActiveMQ包：activemq-all-5.15.3.jar</li>
<li>commons: commons-pool2-2.5.0.jar<br><img src="https://upload-images.jianshu.io/upload_images/3110861-5db3fae9c0723c46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图1.png"><a id="more"></a>
</li>
</ul>
<p>######2). 项目配置<br>I. 配置ConnectionFactory<br>ConnectionFactory是用于产生到JMS服务器的链接的，Spring为我们提供了多个ConnectionFactory，有SingleConnectionFactory和CachingConnectionFactory。</p>
<ul>
<li>SingleConnectionFactory对于建立JMS服务器链接的请求会一直返回同一个链接，并且会忽略Connection的close方法调用。</li>
<li>CachingConnectionFactory继承了SingleConnectionFactory，所以它拥有SingleConnectionFactory的所有功能，同时它还新增了缓存功能，它可以缓存Session、MessageProducer和MessageConsumer。</li>
</ul>
<p>ActiveMQ为我们提供了一个PooledConnectionFactory，通过往里面注入一个ActiveMQConnectionFactory可以用来将Connection、Session和MessageProducer池化，这样可以大大的减少我们的资源消耗。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="line">&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;</span><br><span class="line">	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:context=&quot;http://www.springframework.org/schema/context&quot;</span><br><span class="line">	xmlns:jms=&quot;http://www.springframework.org/schema/jms&quot;</span><br><span class="line">	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans  </span><br><span class="line">     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  </span><br><span class="line">     http://www.springframework.org/schema/context  </span><br><span class="line">     http://www.springframework.org/schema/context/spring-context-3.0.xsd  </span><br><span class="line">    http://www.springframework.org/schema/beans </span><br><span class="line">    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  </span><br><span class="line">    http://www.springframework.org/schema/jms </span><br><span class="line">    http://www.springframework.org/schema/jms/spring-jms-3.0.xsd&quot;&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 自动扫描和管理Bean配置 --&gt;</span><br><span class="line">	&lt;context:component-scan base-package=&quot;com.mazaiting&quot;/&gt;	</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 真正可以产生Connection的ConnectionFactory，由对应的JMS服务厂商提供 --&gt;</span><br><span class="line">	&lt;bean id=&quot;targetConnectionFactory&quot; class=&quot;org.apache.activemq.ActiveMQConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;brokerURL&quot; value=&quot;tcp://localhost:61616&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!--  ActiveMQ为我们提供了一个PooledConnectionFactory，通过往里面注入一个ActiveMQConnectionFactory可以用来将Connection、Session和MessageProducer池化，这样可以大大的减少我们的资源消耗。 --&gt;</span><br><span class="line">	&lt;bean id=&quot;pooledConnectionFactory&quot; class=&quot;org.apache.activemq.pool.PooledConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;targetConnectionFactory&quot;/&gt;</span><br><span class="line">		&lt;!-- 最大连接数 --&gt;</span><br><span class="line">		&lt;property name=&quot;maxConnections&quot; value=&quot;10&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- Spring 用于管理真正的ConnectionFactory的ConnectionFactory --&gt;</span><br><span class="line">	&lt;bean id=&quot;connectionFactory&quot; class=&quot;org.springframework.jms.connection.SingleConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory --&gt;</span><br><span class="line">		&lt;property name=&quot;targetConnectionFactory&quot; ref=&quot;pooledConnectionFactory&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">&lt;/beans&gt;</span><br></pre></td></tr></table></figure></p>
<p>II. 配置生产者<br>生产者负责产生消息并发送到JMS服务器，这通常对应的是我们的一个业务逻辑服务实现类。通常是利用Spring为我们提供的JmsTemplate类来实现的，所以配置生产者其实最核心的就是配置进行消息发送的JmsTemplate。对于消息发送者而言，在定义JmsTemplate的时候需要往里面注入一个Spring提供的ConnectionFactory对象。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- Spring 提供的JMS工具类，它可以进行消息的发送、接收等 --&gt;</span><br><span class="line">&lt;bean id=&quot;jmsTemplate&quot; class=&quot;org.springframework.jms.core.JmsTemplate&quot;&gt;</span><br><span class="line">	&lt;!-- 这个ConnectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --&gt;</span><br><span class="line">	&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">&lt;/bean&gt;</span><br></pre></td></tr></table></figure></p>
<p>利用JmsTemplate进行消息发送的时候，我们需要知道消息发送的目的地，即destination。在Jms中有一个用来表示目的地的Destination接口，它里面没有任何方法定义，只是用来做一个标识而已。当我们在使用JmsTemplate进行消息发送时没有指定destination的时候将使用默认的Destination。默认Destination可以通过在定义jmsTemplate bean对象时通过属性defaultDestination或defaultDestinationName来进行注入，defaultDestinationName对应的就是一个普通字符串。在ActiveMQ中实现了两种类型的Destination，一个是点对点的ActiveMQQueue，另一个就是支持订阅/发布模式的ActiveMQTopic。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 队列目的地，点对点 --&gt;</span><br><span class="line">&lt;bean id=&quot;queueDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;</span><br><span class="line">	&lt;constructor-arg value=&quot;queue&quot;/&gt;</span><br><span class="line">&lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 主题目的地，一对多 --&gt;</span><br><span class="line">&lt;bean id=&quot;topicDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQTopic&quot;&gt;</span><br><span class="line">	&lt;constructor-arg value=&quot;topic&quot;/&gt;</span><br><span class="line">&lt;/bean&gt;</span><br></pre></td></tr></table></figure></p>
<p>III. 配置消费者<br>生产者往指定目的地Destination发送消息后，接下来就是消费者对指定目的地的消息进行消费了。通过Spring为我们封装的消息监听容器MessageListenerContainer, 负责接收信息，并把接收到的信息分发给真正的MessageListener进行处理。每个消费者对应每个目的地都需要有对应的MessageListenerContainer。通过在配置MessageConnectionFactory的时候往里面注入一个ConnectionFactory来实现的,在配置一个MessageListenerContainer的时候有三个属性必须指定，一个是表示从哪里监听的ConnectionFactory；一个是表示监听什么的Destination；一个是接收到消息以后进行消息处理的MessageListener。Spring一共为我们提供了两种类型的MessageListenerContainer，SimpleMessageListenerContainer和DefaultMessageListenerContainer。<br>SimpleMessageListenerContainer会在一开始的时候就创建一个会话session和消费者Consumer，并且会使用标准的JMS MessageConsumer.setMessageListener()方法注册监听器让JMS提供者调用监听器的回调函数。它不会动态的适应运行时需要和参与外部的事务管理。兼容性方面，它非常接近于独立的JMS规范，但一般不兼容Java EE的JMS限制。<br>大多数情况下我们还是使用的DefaultMessageListenerContainer，跟SimpleMessageListenerContainer相比，DefaultMessageListenerContainer会动态的适应运行时需要，并且能够参与外部的事务管理。它很好的平衡了对JMS提供者要求低、先进功能如事务参与和兼容Java EE环境。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">	&lt;!-- 队列目的地，点对点 --&gt;</span><br><span class="line">	&lt;bean id=&quot;queueDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;</span><br><span class="line">		&lt;constructor-arg value=&quot;queue&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	&lt;!-- 消息监听器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;consumerMessageListener&quot; class=&quot;com.mazaiting.jms.listener.ConsumerMessageListener&quot;/&gt;</span><br><span class="line">	&lt;!-- 消息监听容器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;jmsContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;messageListener&quot; ref=&quot;consumerMessageListener&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">``` </span><br><span class="line">IV. 完整配置文件</span><br></pre></td></tr></table></figure></p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jms="http://www.springframework.org/schema/jms" xsi:schemalocation="http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-3.0.xsd  
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    http://www.springframework.org/schema/jms 
    http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">

<pre><code>&lt;!-- 自动扫描和管理Bean配置 --&gt;
&lt;context:component-scan base-package=&quot;com.mazaiting&quot;/&gt;    

&lt;!-- 真正可以产生Connection的ConnectionFactory，由对应的JMS服务厂商提供 --&gt;
&lt;bean id=&quot;targetConnectionFactory&quot; class=&quot;org.apache.activemq.ActiveMQConnectionFactory&quot;&gt;
    &lt;property name=&quot;brokerURL&quot; value=&quot;tcp://localhost:61616&quot;/&gt;
&lt;/bean&gt;

&lt;!--  ActiveMQ为我们提供了一个PooledConnectionFactory，通过往里面注入一个ActiveMQConnectionFactory可以用来将Connection、Session和MessageProducer池化，这样可以大大的减少我们的资源消耗。 --&gt;
&lt;bean id=&quot;pooledConnectionFactory&quot; class=&quot;org.apache.activemq.pool.PooledConnectionFactory&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;targetConnectionFactory&quot;/&gt;
    &lt;!-- 最大连接数 --&gt;
    &lt;property name=&quot;maxConnections&quot; value=&quot;10&quot;/&gt;
&lt;/bean&gt;

&lt;!-- Spring 用于管理真正的ConnectionFactory的ConnectionFactory --&gt;
&lt;bean id=&quot;connectionFactory&quot; class=&quot;org.springframework.jms.connection.SingleConnectionFactory&quot;&gt;
    &lt;!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory --&gt;
    &lt;property name=&quot;targetConnectionFactory&quot; ref=&quot;pooledConnectionFactory&quot;/&gt;
&lt;/bean&gt;

&lt;!-- Spring 提供的JMS工具类，它可以进行消息的发送、接收等 --&gt;
&lt;bean id=&quot;jmsTemplate&quot; class=&quot;org.springframework.jms.core.JmsTemplate&quot;&gt;
    &lt;!-- 这个ConnectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
&lt;/bean&gt;

&lt;!-- 队列目的地，点对点 --&gt;
&lt;bean id=&quot;queueDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;
    &lt;constructor-arg value=&quot;queue&quot;/&gt;
&lt;/bean&gt;
&lt;!-- 消息监听器 --&gt;
&lt;bean id=&quot;consumerMessageListener&quot; class=&quot;com.mazaiting.jms.listener.ConsumerMessageListener&quot;/&gt;
&lt;!-- 消息监听容器 --&gt;
&lt;bean id=&quot;jmsContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot;/&gt;
    &lt;property name=&quot;messageListener&quot; ref=&quot;consumerMessageListener&quot;/&gt;
&lt;/bean&gt;

&lt;!-- 主题目的地，一对多 --&gt;
&lt;bean id=&quot;topicDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQTopic&quot;&gt;
    &lt;constructor-arg value=&quot;topic&quot;/&gt;
&lt;/bean&gt;
</code></pre><p></p></beans><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">######3). 创建Java代码</span><br><span class="line">I. 在com.mazaiting.jms.service包下创建ProducerService接口</span><br></pre></td></tr></table></figure><p></p>
<p>public interface ProducerService {<br>    public void sendMessage(Destination destination, final String message);<br>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">II. 在com.mazaiting.jms.service.impl包下创建ProducerServiceImpl类</span><br></pre></td></tr></table></figure></p>
<p>@Service<br>public class ProducerServiceImpl implements ProducerService{<br>    private JmsTemplate jmsTemplate;</p>
<pre><code>/**
 * 发送消息
 * @param destination 目的地
 * @param message 消息
 * @throws JmsException 
 */
@Override
public void sendMessage(Destination destination, final String message) {
    System.out.println(&quot;-------------生产者发送消息---------------&quot;);
    System.out.println(&quot;-------------生产者发了一个消息：&quot; + message);
    jmsTemplate.send(destination, new MessageCreator() {

        @Override
        public Message createMessage(Session session) throws JMSException {
            return session.createTextMessage(message);
        }
    });
}

public JmsTemplate getJmsTemplate() {
    return jmsTemplate;
}

@Resource
public void setJmsTemplate(JmsTemplate jmsTemplate) {
    this.jmsTemplate = jmsTemplate;
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">III. 在com.mazaiting.jms.listener下创建ConsumerMessageListener类</span><br></pre></td></tr></table></figure></p>
<p>public class ConsumerMessageListener implements MessageListener{</p>
<pre><code>@Override
public void onMessage(Message message) {
    // 判断是否为纯文本消息
    if (message instanceof TextMessage) {
        TextMessage textMessage = (TextMessage) message;
        System.out.println(&quot;接收到纯文本消息：&quot;);
        try {
            System.out.println(&quot;消息的内容是： &quot; + textMessage.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IV. 在com.mazaiting.jms包下创建ProducerConsumerTest测试类</span><br></pre></td></tr></table></figure></p>
<p>public class ProducerConsumerTest {<br>    private ApplicationContext context;<br>    private ProducerService producerService;<br>    private Destination destination;<br>    @Before<br>    public void onInit() {<br>        context = new ClassPathXmlApplicationContext(“classpath:bean.xml”);<br>        producerService = (ProducerService) context.getBean(“producerServiceImpl”);<br>        destination = (Destination) context.getBean(“queueDestination”);<br>    }</p>
<pre><code>@Test
public void sendTest() {
    for (int i = 0; i &lt; 2; i++) {
        producerService.sendMessage(destination, &quot;你好，生产者！ 这是消息&quot; + (i+1));
    }
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">V. 测试</span><br><span class="line">- 先运行activemq.bat文件</span><br><span class="line">- 在运行测试方法</span><br><span class="line">![图2.png](https://upload-images.jianshu.io/upload_images/3110861-b87a292dd90b4c56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">####2. 消息监听器(MessageListener)</span><br><span class="line">pring整合JMS的应用中我们在定义消息监听器的时候一共可以定义三种类型的消息监听器，分别是MessageListener、SessionAwareMessageListener和MessageListenerAdapter。</span><br><span class="line">######1).  MessageListener</span><br><span class="line">MessageListener是最原始的消息监听器，它是JMS规范中定义的一个接口。其中定义了一个用于处理接收到的消息的onMessage方法，该方法只接收一个Message参数。</span><br></pre></td></tr></table></figure></p>
<p>public class ConsumerMessageListener implements MessageListener{</p>
<pre><code>@Override
public void onMessage(Message message) {
    // 判断是否为纯文本消息
    if (message instanceof TextMessage) {
        TextMessage textMessage = (TextMessage) message;
        System.out.println(&quot;接收到纯文本消息：&quot;);
        try {
            System.out.println(&quot;消息的内容是： &quot; + textMessage.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">######2). SessionAwareMessageListener</span><br><span class="line">SessionAwareMessageListener是Spring为我们提供的，它不是标准的JMS MessageListener。MessageListener的设计只是纯粹用来接收消息的，假如我们在使用MessageListener处理接收到的消息时我们需要发送一个消息通知对方我们已经收到这个消息了，那么这个时候我们就需要在代码里面去重新获取一个Connection或Session。SessionAwareMessageListener的设计就是为了方便我们在接收到消息后发送一个回复的消息，它同样为我们提供了一个处理接收到的消息的onMessage方法，但是这个方法可以同时接收两个参数，一个是表示当前接收到的消息Message，另一个就是可以用来发送消息的Session对象。</span><br><span class="line">I. 定义ConsumerSessionAwareMessageListener</span><br></pre></td></tr></table></figure></p>
<p>public class ConsumerSessionAwareMessageListener implements SessionAwareMessageListener<textmessage>{<br>    private Destination destination;<br>    @Override<br>    public void onMessage(TextMessage message, Session session) throws JMSException {<br>        System.out.println(“收到一条消息”);<br>        System.out.println(“消息的内容是： “ + message.getText());<br>        // 创建消息生产者<br>        MessageProducer producer = session.createProducer(destination);<br>        // 创建文本消息<br>        Message textMessage = session.createTextMessage(“ConsumerSessionAwareMessageListener…”);<br>        // 发送消息<br>        producer.send(textMessage);<br>    }<br>    public Destination getDestination() {<br>        return destination;<br>    }<br>    public void setDestination(Destination destination) {<br>        this.destination = destination;<br>    }<br>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">II. 在Spring的配置文件中配置该消息监听器将处理来自一个叫sessionAwareQueue的目的地的消息，并且往该MessageListener中通过set方法注入其属性destination的值为queueDestination。这样当我们的SessionAwareMessageListener接收到消息之后就会往queueDestination发送一个消息。</span><br><span class="line">bean.xml文件中添加配置</span><br></pre></td></tr></table></figure></textmessage></p>
<pre><code>&lt;!-- SessionAwareQueue目的地 --&gt;
&lt;bean id=&quot;sessionAwareQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;
    &lt;constructor-arg value=&quot;sessionAwareQueue&quot;/&gt;
&lt;/bean&gt;
&lt;!-- 可以获取session的MessageListener --&gt;
&lt;bean id=&quot;consumerSessionAwareMessageListener&quot; class=&quot;com.mazaiting.jms.listener.ConsumerSessionAwareMessageListener&quot;&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot;/&gt;
&lt;/bean&gt;
&lt;!-- 消息监听容器 --&gt;
&lt;bean id=&quot;sessionAwareListenerContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;sessionAwareQueue&quot;/&gt;
    &lt;property name=&quot;messageListener&quot; ref=&quot;consumerSessionAwareMessageListener&quot;/&gt;
&lt;/bean&gt;
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">III. 测试类</span><br></pre></td></tr></table></figure>
<p>public class ProducerConsumerTest {<br>    private ApplicationContext context;<br>    private ProducerService producerService;<br>    private Destination destination;<br>    @Before<br>    public void onInit() {<br>        context = new ClassPathXmlApplicationContext(“classpath:bean.xml”);<br>        producerService = (ProducerService) context.getBean(“producerServiceImpl”);<br>//        destination = (Destination) context.getBean(“queueDestination”);<br>        destination = (Destination) context.getBean(“sessionAwareQueue”);<br>    }</p>
<pre><code>@Test
public void sendTest() {
    for (int i = 0; i &lt; 2; i++) {
        producerService.sendMessage(destination, &quot;你好，生产者！ 这是消息&quot; + (i+1));
    }
}

@Test
public void sessionAwareMessageListenerTest() {
    producerService.sendMessage(destination, &quot;测试SessionAwareMessageListener&quot;);
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">IV. 测试</span><br><span class="line">![图3.png](https://upload-images.jianshu.io/upload_images/3110861-ecc1579e089eb08d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">######3). MessageListenerAdapter</span><br><span class="line">MessageListenerAdapter类实现了MessageListener接口和SessionAwareMessageListener接口，它的主要作用是将接收到的消息进行类型转换，然后通过反射的形式把它交给一个普通的Java类进行处理。</span><br><span class="line">MessageListenerAdapter会把接收到的消息做如下转换：</span><br><span class="line">- TextMessage转换为String对象；</span><br><span class="line">- BytesMessage转换为byte数组；</span><br><span class="line">- MapMessage转换为Map对象；</span><br><span class="line">- ObjectMessage转换为对应的Serializable对象。</span><br><span class="line"></span><br><span class="line">I. 创建ConsumerListener</span><br></pre></td></tr></table></figure></p>
<p>public class ConsumerListener {<br>    public void handleMessage(String message) {<br>        System.out.println(“ConsumerListener通过handleMessage发送到一个纯文本消息，消息内容是：” + message);<br>    }</p>
<pre><code>public void receiveMessage(String message) {
    System.out.println(&quot;ConsumerListener通过receiveMessage接收到一个纯文本消息，消息内容是：&quot; + message);
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">II. bean.xml添加配置</span><br></pre></td></tr></table></figure></p>
<pre><code>&lt;!-- 测试消息监听适配器的队列目的地-MessageListenerAdapter --&gt;
&lt;bean id=&quot;adapterQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;
    &lt;constructor-arg&gt;
        &lt;value&gt;adapterQueue&lt;/value&gt;
    &lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;!-- 适配器 --&gt;
&lt;bean id=&quot;messageListenerAdapter&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;
    &lt;property name=&quot;delegate&quot;&gt;
        &lt;bean class=&quot;com.mazaiting.jms.listener.ConsumerListener&quot;/&gt;
    &lt;/property&gt;
    &lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receiveMessage&quot;/&gt;
&lt;/bean&gt;
&lt;!-- 或者使用此方式配置适配器 --&gt;
</code></pre><!--     <bean id="messageListenerAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
        <constructor-arg>
            <bean class="com.mazaiting.jms.listener.ConsumerListener"/>
        </constructor-arg>
    </bean> -->
<pre><code>&lt;!-- 消息监听适配器对应的监听容器 --&gt;
&lt;bean id=&quot;messageListenerAdapterContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;adapterQueue&quot;/&gt;
    &lt;property name=&quot;messageListener&quot; ref=&quot;messageListenerAdapter&quot;/&gt;
&lt;/bean&gt;
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">III. 测试代码</span><br></pre></td></tr></table></figure>
<p>public class ProducerConsumerTest {<br>    private ApplicationContext context;<br>    private ProducerService producerService;<br>    private Destination destination;<br>    @Before<br>    public void onInit() {<br>        context = new ClassPathXmlApplicationContext(“classpath:bean.xml”);<br>        producerService = (ProducerService) context.getBean(“producerServiceImpl”);<br>//        destination = (Destination) context.getBean(“queueDestination”);<br>//        destination = (Destination) context.getBean(“sessionAwareQueue”);<br>        destination = (Destination) context.getBean(“adapterQueue”);<br>    }</p>
<pre><code>@Test
public void messageListenerAdapterTest() {
    producerService.sendMessage(destination, &quot;测试MessageListenerAdapter&quot;);
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">IV. 结果</span><br><span class="line">![图4.png](https://upload-images.jianshu.io/upload_images/3110861-6ca3cf3e38574b0f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">V. 如果我们不指定MessageListenerAdapter的defaultListenerMethod属性， 运行上述代码时控制台会输出如下结果：</span><br><span class="line">![图5.png](https://upload-images.jianshu.io/upload_images/3110861-3886eb77704285bb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">######4). MessageListenerAdapter除了会自动的把一个普通Java类当做MessageListener来处理接收到的消息，另一个主要的功能是可以**自动的发送返回消息**。</span><br><span class="line">**方式一：**</span><br><span class="line">I. 修改生产者ProducerServiceImpl代码</span><br></pre></td></tr></table></figure></p>
<p>@Service<br>public class ProducerServiceImpl implements ProducerService{<br>    @Autowired<br>    private JmsTemplate jmsTemplate;</p>
<pre><code>@Autowired
@Qualifier(&quot;responseQueue&quot;)
private Destination responseDestination;

/**
 * 发送消息
 * @param destination 目的地
 * @param message 消息
 * @throws JmsException 
 */
@Override
public void sendMessage(Destination destination, final String message) {
    System.out.println(&quot;-------------生产者发送消息---------------&quot;);
    System.out.println(&quot;-------------生产者发了一个消息：&quot; + message);
    jmsTemplate.send(destination, new MessageCreator() {

        @Override
        public Message createMessage(Session session) throws JMSException {
            TextMessage textMessage = session.createTextMessage(message);
            textMessage.setJMSReplyTo(responseDestination);
            return textMessage;
        }
    });
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">II. 创建ResponseQueueListener</span><br></pre></td></tr></table></figure></p>
<p>public class ResponseQueueListener implements MessageListener{</p>
<pre><code>@Override
public void onMessage(Message message) {
    if (message instanceof TextMessage) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println(&quot;发送到responseQueue的一个文本消息，内容是： &quot; + textMessage.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">III. bean.xml添加配置</span><br></pre></td></tr></table></figure></p>
<pre><code>&lt;!-- 用于测试消息回复 --&gt;
&lt;bean id=&quot;responseQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;
    &lt;constructor-arg&gt;
        &lt;value&gt;responseQueue&lt;/value&gt;
    &lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;!-- responseQueue对应的监听器 --&gt;
&lt;bean id=&quot;responseQueueListener&quot; class=&quot;com.mazaiting.jms.listener.ResponseQueueListener&quot;/&gt;
&lt;!-- responseQueue对应的监听容器 --&gt;
&lt;bean id=&quot;responseQueueMessageListenerContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;responseQueue&quot;/&gt;
    &lt;property name=&quot;messageListener&quot; ref=&quot;responseQueueListener&quot;/&gt;
&lt;/bean&gt;
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IV. 修改ConsumerListener</span><br></pre></td></tr></table></figure>
<p>public class ConsumerListener {<br>    public void handleMessage(String message) {<br>        System.out.println(“ConsumerListener通过handleMessage发送到一个纯文本消息，消息内容是：” + message);<br>    }</p>
<pre><code>public String receiveMessage(String message) {
    System.out.println(&quot;ConsumerListener通过receiveMessage接收到一个纯文本消息，消息内容是：&quot; + message);
    return &quot;这是ConsumerListener对象的receiveMessage方法的返回值。&quot;;
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">V. 执行测试方法messageListenerAdapterTest</span><br><span class="line">![图6.png](https://upload-images.jianshu.io/upload_images/3110861-006d9a80d94cbce3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">**方式二：通过MessageListenerAdapter的defaultResponseDestination属性来指定。**</span><br><span class="line">I. 创建DefaultResponseQueueListener</span><br></pre></td></tr></table></figure></p>
<p>public class DefaultResponseQueueListener implements MessageListener{</p>
<pre><code>@Override
public void onMessage(Message message) {
    if (message instanceof TextMessage) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println(&quot;DefaultResponseQueueListener接收到发送到defaultResponseQueue的一个文本消息，内容是：&quot; + textMessage.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }  
    }
}
</code></pre><p>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">II. bean.xml添加配置</span><br></pre></td></tr></table></figure></p>
<pre><code>&lt;!-- 适配器 --&gt;
&lt;bean id=&quot;messageListenerAdapter&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;
    &lt;property name=&quot;delegate&quot;&gt;
        &lt;bean class=&quot;com.mazaiting.jms.listener.ConsumerListener&quot;/&gt;
    &lt;/property&gt;
    &lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receiveMessage&quot;/&gt; 
    &lt;!-- 添加配置 --&gt;
    &lt;property name=&quot;defaultResponseDestination&quot; ref=&quot;defaultResponseQueue&quot;/&gt;
&lt;/bean&gt;

&lt;!-- 默认的消息回复队列 --&gt;
&lt;bean id=&quot;defaultResponseQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;
    &lt;constructor-arg&gt;
        &lt;value&gt;defaultResponseQueue&lt;/value&gt;
    &lt;/constructor-arg&gt;
&lt;/bean&gt;
&lt;!-- defaultResponseQueue对应的监听器 --&gt;
&lt;bean id=&quot;defaultResponseQueueListener&quot; class=&quot;com.mazaiting.jms.listener.DefaultResponseQueueListener&quot;/&gt;
&lt;!-- defaultResponseQueue对应的监听容器 --&gt;
&lt;bean id=&quot;defaultResponseQueueMessageListenerContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;
    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;
    &lt;property name=&quot;destination&quot; ref=&quot;defaultResponseQueue&quot;/&gt;
    &lt;property name=&quot;messageListener&quot; ref=&quot;defaultResponseQueueListener&quot;/&gt;
&lt;/bean&gt;
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">III. 执行测试方法messageListenerAdapterTest</span><br><span class="line">![图7.png](https://upload-images.jianshu.io/upload_images/3110861-78d6dabad2e9c190.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)</span><br><span class="line"></span><br><span class="line">######5). 消息转换器MessageConverter</span><br><span class="line">MessageConverter的作用主要有两方面，一方面它可以把我们的非标准化Message对象转换成我们的目标Message对象，这主要是用在发送消息的时候；另一方面它又可以把我们的Message对象转换成对应的目标对象，这主要是用在接收消息的时候。</span><br><span class="line">I. 创建邮件对象</span><br></pre></td></tr></table></figure>
<p>/**</p>
<ul>
<li>邮件 Bean</li>
<li><p>@author mazaiting<br>*/<br>public class Email implements Serializable{<br> private static final long serialVersionUID = 1L;<br> private String receiver;<br> private String title;<br> private String content;</p>
<p> public Email(String receiver, String title, String content) {</p>
<pre><code>this.receiver = receiver;
this.title = title;
this.content = content;
</code></pre><p> }<br> public String getReceiver() {</p>
<pre><code>return receiver;
</code></pre><p> }<br> public void setReceiver(String receiver) {</p>
<pre><code>this.receiver = receiver;
</code></pre><p> }<br> public String getTitle() {</p>
<pre><code>return title;
</code></pre><p> }<br> public void setTitle(String title) {</p>
<pre><code>this.title = title;
</code></pre><p> }<br> public String getContent() {</p>
<pre><code>return content;
</code></pre><p> }<br> public void setContent(String content) {</p>
<pre><code>this.content = content;
</code></pre><p> }<br> @Override<br> public String toString() {</p>
<pre><code>StringBuilder builder = new StringBuilder();
builder.append(&quot;Email [receiver=&quot;);
builder.append(receiver);
builder.append(&quot;, title=&quot;);
builder.append(title);
builder.append(&quot;, content=&quot;);
builder.append(content);
builder.append(&quot;]&quot;);
return builder.toString();
</code></pre><p> }<br>}</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">II. 创建服务接口ProducerService ，并实现</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>public interface ProducerService {<br>    void sendMessage(Destination destination, Serializable obj);<br>}<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">```</span><br><span class="line">@Service</span><br><span class="line">public class ProducerServiceImpl implements ProducerService&#123;</span><br><span class="line"></span><br><span class="line">	@Autowired</span><br><span class="line">	private JmsTemplate jmsTemplate;</span><br><span class="line">	</span><br><span class="line">	@Override</span><br><span class="line">	public void sendMessage(Destination destination, Serializable obj) &#123;</span><br><span class="line">		// 未使用MessageConverter</span><br><span class="line">		/*jmsTemplate.send(destination, new MessageCreator() &#123;</span><br><span class="line">			</span><br><span class="line">			@Override</span><br><span class="line">			public Message createMessage(Session session) throws JMSException &#123;</span><br><span class="line">				return session.createObjectMessage(obj);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;);*/</span><br><span class="line">		// 使用MessageConverter, JmsTemplate就会在其内部调用预定的MessageConverter对我们的消息对象进行转换，然后再进行发送。</span><br><span class="line">		jmsTemplate.convertAndSend(destination, obj);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>III. 创建消息转换器对象EmailMessageConverter<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public class EmailMessageConverter implements MessageConverter&#123;</span><br><span class="line"></span><br><span class="line">	@Override</span><br><span class="line">	public Message toMessage(Object object, Session session) throws JMSException &#123;</span><br><span class="line">		return session.createObjectMessage((Serializable) object);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	@Override</span><br><span class="line">	public Object fromMessage(Message message) throws JMSException, MessageConversionException &#123;</span><br><span class="line">		ObjectMessage objMessage = (ObjectMessage) message;</span><br><span class="line">		return objMessage.getObject();</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>IV. 创建消息监听器ConsumerMessageListener<br><figure class="highlight plain"><figcaption><span>class ConsumerMessageListener implements MessageListener&#123;</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">	@Override</span><br><span class="line">	public void onMessage(Message message) &#123;</span><br><span class="line">		if (message instanceof ObjectMessage) &#123;</span><br><span class="line">			ObjectMessage objMessage = (ObjectMessage) message;</span><br><span class="line">			try &#123;</span><br><span class="line">				Object obj = objMessage.getObject();</span><br><span class="line">				Email email = (Email) obj;</span><br><span class="line">				System.out.println(&quot;接收到一个ObjectMessage,包含Email对象&quot;);</span><br><span class="line">				System.out.println(email.toString());</span><br><span class="line">			&#125; catch (JMSException e) &#123;</span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>V. 修改bean-converter.xml文件(由bean.xml文件复制而来，删除了不必要的东西)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span><br><span class="line">&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;</span><br><span class="line">	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:context=&quot;http://www.springframework.org/schema/context&quot;</span><br><span class="line">	xmlns:jms=&quot;http://www.springframework.org/schema/jms&quot;</span><br><span class="line">	xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans  </span><br><span class="line">     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  </span><br><span class="line">     http://www.springframework.org/schema/context  </span><br><span class="line">     http://www.springframework.org/schema/context/spring-context-3.0.xsd  </span><br><span class="line">    http://www.springframework.org/schema/beans </span><br><span class="line">    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  </span><br><span class="line">    http://www.springframework.org/schema/jms </span><br><span class="line">    http://www.springframework.org/schema/jms/spring-jms-3.0.xsd&quot;&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 自动扫描和管理Bean配置 --&gt;</span><br><span class="line">	&lt;context:component-scan base-package=&quot;com.mazaiting.jms.converter&quot;/&gt;	</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 真正可以产生Connection的ConnectionFactory，由对应的JMS服务厂商提供 --&gt;</span><br><span class="line">	&lt;bean id=&quot;targetConnectionFactory&quot; class=&quot;org.apache.activemq.ActiveMQConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;brokerURL&quot; value=&quot;tcp://localhost:61616&quot;/&gt;</span><br><span class="line">		&lt;!-- 如果传输对象，必须设置这句为true --&gt;</span><br><span class="line">		&lt;property name=&quot;trustAllPackages&quot; value=&quot;true&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!--  ActiveMQ为我们提供了一个PooledConnectionFactory，通过往里面注入一个ActiveMQConnectionFactory可以用来将Connection、Session和MessageProducer池化，这样可以大大的减少我们的资源消耗。 --&gt;</span><br><span class="line">	&lt;bean id=&quot;pooledConnectionFactory&quot; class=&quot;org.apache.activemq.pool.PooledConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;targetConnectionFactory&quot;/&gt;</span><br><span class="line">		&lt;!-- 最大连接数 --&gt;</span><br><span class="line">		&lt;property name=&quot;maxConnections&quot; value=&quot;10&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- Spring 用于管理真正的ConnectionFactory的ConnectionFactory --&gt;</span><br><span class="line">	&lt;bean id=&quot;connectionFactory&quot; class=&quot;org.springframework.jms.connection.SingleConnectionFactory&quot;&gt;</span><br><span class="line">		&lt;!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory --&gt;</span><br><span class="line">		&lt;property name=&quot;targetConnectionFactory&quot; ref=&quot;pooledConnectionFactory&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 类型转换器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;emailMessageConverter&quot; class=&quot;com.mazaiting.jms.converter.converter.EmailMessageConverter&quot;/&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- Spring 提供的JMS工具类，它可以进行消息的发送、接收等 --&gt;</span><br><span class="line">	&lt;bean id=&quot;jmsTemplate&quot; class=&quot;org.springframework.jms.core.JmsTemplate&quot;&gt;</span><br><span class="line">		&lt;!-- 这个ConnectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 --&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">		&lt;!-- 消息转换器 --&gt;</span><br><span class="line">		&lt;property name=&quot;messageConverter&quot; ref=&quot;emailMessageConverter&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 队列目的地，点对点 --&gt;</span><br><span class="line">	&lt;bean id=&quot;queueDestination&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;</span><br><span class="line">		&lt;constructor-arg value=&quot;queue&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	&lt;!-- 消息监听器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;consumerMessageListener&quot; class=&quot;com.mazaiting.jms.converter.listener.ConsumerMessageListener&quot;/&gt;</span><br><span class="line">	&lt;!-- 消息监听容器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;jmsContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;messageListener&quot; ref=&quot;consumerMessageListener&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">	&lt;!-- 测试消息监听适配器的队列目的地-MessageListenerAdapter --&gt;</span><br><span class="line">	&lt;bean id=&quot;adapterQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;</span><br><span class="line">		&lt;constructor-arg&gt;</span><br><span class="line">			&lt;value&gt;adapterQueue&lt;/value&gt;</span><br><span class="line">		&lt;/constructor-arg&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	&lt;!-- 适配器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;messageListenerAdapter&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;delegate&quot;&gt;</span><br><span class="line">			&lt;bean class=&quot;com.mazaiting.jms.listener.ConsumerListener&quot;/&gt;</span><br><span class="line">		&lt;/property&gt;</span><br><span class="line">		&lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receiveMessage&quot;/&gt; </span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	&lt;!-- 消息监听适配器对应的监听容器 --&gt;</span><br><span class="line">	&lt;bean id=&quot;messageListenerAdapterContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;</span><br><span class="line">		&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;destination&quot; ref=&quot;adapterQueue&quot;/&gt;</span><br><span class="line">		&lt;property name=&quot;messageListener&quot; ref=&quot;messageListenerAdapter&quot;/&gt;</span><br><span class="line">	&lt;/bean&gt;</span><br><span class="line">	</span><br><span class="line">&lt;/beans&gt;</span><br></pre></td></tr></table></figure></p>
<p>VI. 测试类<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public class ProducerConsumerConverterTest &#123;</span><br><span class="line">	private ApplicationContext context;</span><br><span class="line">	private ProducerService producerService;</span><br><span class="line">	private Destination destination;</span><br><span class="line">	@Before</span><br><span class="line">	public void onInit() &#123;</span><br><span class="line">		context = new ClassPathXmlApplicationContext(&quot;classpath:bean-converter.xml&quot;);</span><br><span class="line">		producerService = (ProducerService) context.getBean(&quot;producerServiceImpl&quot;);</span><br><span class="line">		destination = (Destination) context.getBean(&quot;queueDestination&quot;);</span><br><span class="line">//		destination = (Destination) context.getBean(&quot;adapterQueue&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	@Test</span><br><span class="line">	public void objMessageTest() &#123;</span><br><span class="line">		Email email = new Email(&quot;lisi@xxx.com&quot;, &quot;主题&quot;, &quot;内容&quot;);</span><br><span class="line">		producerService.sendMessage(destination, email);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>VII. 执行测试<br><img src="https://upload-images.jianshu.io/upload_images/3110861-42801b74593a4b2d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图8.png"></p>
<p>VIII. 修改ConsumerMessageListener代码为<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">public class ConsumerMessageListener implements MessageListener&#123;</span><br><span class="line">	/**</span><br><span class="line">	 * 消息转换器</span><br><span class="line">	 */</span><br><span class="line">	@Autowired</span><br><span class="line">	@Qualifier(&quot;emailMessageConverter&quot;)</span><br><span class="line">	private MessageConverter messageConverter;</span><br><span class="line">	@Override</span><br><span class="line">	public void onMessage(Message message) &#123;</span><br><span class="line">		if (message instanceof ObjectMessage) &#123;</span><br><span class="line">//			ObjectMessage objMessage = (ObjectMessage) message;</span><br><span class="line">			try &#123;</span><br><span class="line">//				Object obj = objMessage.getObject();</span><br><span class="line">//				Email email = (Email) obj;</span><br><span class="line">				Email email = (Email) messageConverter.fromMessage(message);</span><br><span class="line">				System.out.println(&quot;接收到一个ObjectMessage,包含Email对象&quot;);</span><br><span class="line">				System.out.println(email.toString());</span><br><span class="line">			&#125; catch (JMSException e) &#123;</span><br><span class="line">				e.printStackTrace();</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>Ⅸ. 执行结果<br><img src="https://upload-images.jianshu.io/upload_images/3110861-9b7202609da8c3d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图9.png"></p>
<p>Ⅹ. 使用MessageListenerAdapter做消息监听器<br>当我们使用MessageListenerAdapter来作为消息监听器的时候，我们可以为它指定一个对应的MessageConverter，这样Spring在处理接收到的消息的时候就会自动地利用我们指定的MessageConverter对它进行转换，然后把转换后的Java对象作为参数调用指定的消息处理方法。</p>
<ul>
<li><p>创建ConsumerListener </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public class ConsumerListener &#123;</span><br><span class="line">	public void receiveMessage(String message) &#123;</span><br><span class="line">		System.out.println(&quot;ConsumerListener通过receiveMessage接收到一个纯文本消息，消息内容是：&quot; + message);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	public void receiveMessage(Email email) &#123;</span><br><span class="line">        System.out.println(&quot;接收到一个包含Email的ObjectMessage。&quot;);  </span><br><span class="line">        System.out.println(email); </span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>修改bean.converter.xml</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- 测试消息监听适配器的队列目的地-MessageListenerAdapter --&gt;</span><br><span class="line">&lt;bean id=&quot;adapterQueue&quot; class=&quot;org.apache.activemq.command.ActiveMQQueue&quot;&gt;</span><br><span class="line">	&lt;constructor-arg&gt;</span><br><span class="line">		&lt;value&gt;adapterQueue&lt;/value&gt;</span><br><span class="line">	&lt;/constructor-arg&gt;</span><br><span class="line">&lt;/bean&gt;</span><br><span class="line">&lt;!-- 适配器 --&gt;</span><br><span class="line">&lt;bean id=&quot;messageListenerAdapter&quot; class=&quot;org.springframework.jms.listener.adapter.MessageListenerAdapter&quot;&gt;</span><br><span class="line">	&lt;property name=&quot;delegate&quot;&gt;</span><br><span class="line">		&lt;bean class=&quot;com.mazaiting.jms.converter.listener.ConsumerListener&quot;/&gt;</span><br><span class="line">	&lt;/property&gt;</span><br><span class="line">	&lt;property name=&quot;defaultListenerMethod&quot; value=&quot;receiveMessage&quot;/&gt; </span><br><span class="line">	&lt;!-- 配置消息转换器 --&gt;</span><br><span class="line">	&lt;property name=&quot;messageConverter&quot; ref=&quot;emailMessageConverter&quot;/&gt;</span><br><span class="line">&lt;/bean&gt;</span><br><span class="line">&lt;!-- 消息监听适配器对应的监听容器 --&gt;</span><br><span class="line">&lt;bean id=&quot;messageListenerAdapterContainer&quot; class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;</span><br><span class="line">	&lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot;/&gt;</span><br><span class="line">	&lt;property name=&quot;destination&quot; ref=&quot;adapterQueue&quot;/&gt;</span><br><span class="line">	&lt;property name=&quot;messageListener&quot; ref=&quot;messageListenerAdapter&quot;/&gt;</span><br><span class="line">&lt;/bean&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>测试类</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public class ProducerConsumerConverterTest &#123;</span><br><span class="line">	private ApplicationContext context;</span><br><span class="line">	private ProducerService producerService;</span><br><span class="line">	private Destination destination;</span><br><span class="line">	@Before</span><br><span class="line">	public void onInit() &#123;</span><br><span class="line">		context = new ClassPathXmlApplicationContext(&quot;classpath:bean-converter.xml&quot;);</span><br><span class="line">		producerService = (ProducerService) context.getBean(&quot;producerServiceImpl&quot;);</span><br><span class="line">//		destination = (Destination) context.getBean(&quot;queueDestination&quot;);</span><br><span class="line">		destination = (Destination) context.getBean(&quot;adapterQueue&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	@Test</span><br><span class="line">	public void objMessageTest() &#123;</span><br><span class="line">		Email email = new Email(&quot;lisi@xxx.com&quot;, &quot;主题&quot;, &quot;内容&quot;);</span><br><span class="line">		producerService.sendMessage(destination, email);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>执行效果<br><img src="https://upload-images.jianshu.io/upload_images/3110861-3d4a702aac1a8965.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图10.png"></p>
</li>
</ul>
<p>######6). 事务<br>I. 在jmsContainer中添加<code>sessionTransacted</code>属性即可<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">&lt;bean id=&quot;jmsContainer&quot;  </span><br><span class="line">    class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;  </span><br><span class="line">    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;messageListener&quot; ref=&quot;consumerMessageListener&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;sessionTransacted&quot; value=&quot;true&quot;/&gt;  </span><br><span class="line">&lt;/bean&gt;</span><br></pre></td></tr></table></figure></p>
<p>II. 如果想接收消息和数据库访问处于同一事务中，那么我们就可以配置一个外部的事务管理同时配置一个支持外部事务管理的消息监听容器（如DefaultMessageListenerContainer）。要配置这样一个参与分布式事务管理的消息监听容器，我们可以配置一个JtaTransactionManager，当然底层的JMS ConnectionFactory需要能够支持分布式事务管理，并正确地注册我们的JtaTransactionManager。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;bean id=&quot;jmsContainer&quot;  </span><br><span class="line">    class=&quot;org.springframework.jms.listener.DefaultMessageListenerContainer&quot;&gt;  </span><br><span class="line">    &lt;property name=&quot;connectionFactory&quot; ref=&quot;connectionFactory&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;destination&quot; ref=&quot;queueDestination&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;messageListener&quot; ref=&quot;consumerMessageListener&quot; /&gt;  </span><br><span class="line">    &lt;property name=&quot;transactionManager&quot; ref=&quot;jtaTransactionManager&quot;/&gt;  </span><br><span class="line">&lt;/bean&gt;  </span><br><span class="line">  </span><br><span class="line">&lt;bean id=&quot;jtaTransactionManager&quot; class=&quot;org.springframework.transaction.jta.JtaTransactionManager&quot;/&gt;</span><br></pre></td></tr></table></figure></p>
<p>####3. Transport Connectors配置</p>
<p>######1). Transport Connectors配置<br>ActiveMQ Connecor分为两种：</p>
<ul>
<li>Transport Connector和Network Connector。transport Connector负责client和broker的连接，称为client-to-broker communication；</li>
<li><p>Network Connector负责broker和broker之间的连接，称为broker-to-broker communication<br><img src="https://upload-images.jianshu.io/upload_images/3110861-f2bac201c5845ca5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图11.png"></p>
</li>
<li><p>从broker的角度来看，transport connector是用于接受和监听来自客户端的连接请求的一种机制。可以看到在<transportconnectors>中包含了多个<transportconnector>对象，每一个对象都定义了监听的地址、端口以及使用的协议。不同的<transportconnector>的name和uri属性值必须不同。</transportconnector></transportconnector></transportconnectors></p>
</li>
<li>从客户端的角度来看，transportConnector的URI是用于和broker建立连接，以通过该连接来发送和接受消息。</li>
</ul>
<p>######2). Transport Connector的可用协议</p>
<ul>
<li>传输控制协议  （TCP）</li>
<li>New I/O API协议（NIO）</li>
<li>用户数据包协议（UDP）</li>
<li>SSL协议（Secure Sockets Layer Protocol）</li>
<li>HTTP/HTTPS协议</li>
<li>虚拟机协议（virtual machine protocol， VM）<br>I. 传输控制协议  （TCP）<br>由于TCP具有可靠传输的特性，它在ActiveMQ中也是最长使用的一种协议。在默认的配置中，TCP连接的端口为61616.TCP Connector的URI的配置语法如下：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tcp://hostname:port?key=value&amp;key=value</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p><code>tcp://hostname:port</code>为必须部分，剩余的key/value部分为可选部分，不同的key/value用”&amp;”符号分开,<a href="http://activemq.apache.org/tcp-transport-reference.html" target="_blank" rel="noopener">详细介绍</a>。可选部分用于定义broker的一些额外的行为，如假设我们进行如下配置：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;transportConnector　name=”tcp”uri=”tcp://localhost:61616?trace=true”/&gt;</span><br></pre></td></tr></table></figure></p>
<p>则broker会在日志中记录经过这个connector所发送的每一条消息，这对于调试会有很大的帮助。<br>II. New I/O API协议（NIO）<br>NIO是在Java SE 1.4开始引进的，用于提供一种网络编程和访问现代操作系统的底层I/O.NIO中使用最多的两种特性是selector和non-blocking I/O，它们使得开发人员可以使用相同的资源来处理更多的网络连接（如果不使用NIO技术，系统将无法承受这么多的网络连接）。从客户端的角度来看，NIO transport connector与TCP connector是相同的，这是因为NIO connector实际上采用TCP来传输数据。唯一不同的是，NIO transport connector是利用NIO API实现的。这使得NIO在以下几种情况下更为适合：</p>
<ul>
<li>大量的客户端需要连接broker。通常，与broker之间的连接数是受操作系统的线程数限制的，由于相比TCP connector而言，NIO connector会占用更少的线程。所以，当TCP connector无法满足要求时，可以考虑使用NIO进行替代。</li>
<li>broker之间存在严重的网路阻塞。NIO connector会比TCP connector拥有更好的性能，因为它会使用更少的资源。</li>
</ul>
<p>NIO的配置语法与TCP的配置相似，只需将tcp替换成nio即可：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nio://hostname:port?key=value</span><br></pre></td></tr></table></figure></p>
<p>NIO的默认监听端口是61618，它也有trace这个可以，用于决定是否记录所有传输的消息。<br>III. 用户数据包协议（UDP）<br>根据UDP的特性，它一般用于要求传出速率快，且能够忍受丢包发生的情况。你可以使用UDP协议来连接ActiveMQ的UDP connector。它的URI语法与TCP及NIO基本一致：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">udp://hostname:port?key=value</span><br></pre></td></tr></table></figure></p>
<p><a href="http://activemq.apache.org/udp-transport-reference.html" target="_blank" rel="noopener">详细内容</a>,通常以下两种情况可以考虑使用UDP：</p>
<ul>
<li>broker有防火墙的保护，只能通过UDP端口来访问；</li>
<li>消息传送对实时性要求非常高，可以通过UDP来尽可能的消除网络延迟；</li>
</ul>
<p>由于UDP的不可靠特性，所以在使用时，必须考虑丢包时的处理。<br>IV. SSL协议（Secure Sockets Layer Protocol）<br>当broker暴露于不安全的网络环境，而你的数据需要保密时，可以使用SSL。它是用于通过TCP传输加密数据的一种协议，它通过一对钥匙（公钥和私钥）来保证一条安全通道。ActiveMQ提供SSL connector，它的语法如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssl://hostname:port?key=value</span><br></pre></td></tr></table></figure></p>
<p>由于ssl采用TCP进行传输，它的选项跟TCP是一致的，当然如果你需要更加详细的说明，可以参考：<a href="http://activemq.apache.org/ssl-transport-reference.html，另外需要说明的是ssl" target="_blank" rel="noopener">http://activemq.apache.org/ssl-transport-reference.html，另外需要说明的是ssl</a> connector默认监听61617端口。与前3种不同，ssl connector还需要ssl证书来保证其正确运行。JSSE提供了两类文件分别用于存储key和certification，用于存储key的文件称为keystores，存储certification的称为truststores.<br>V. HTTP/HTTPS协议<br> 有些服务器的防火墙设置了只能提供HTTP访问，这时便是HTTP/HTTPS connector的地盘了。ActiveMQ实现的HTTP/HTTPS协议用于传输XML数据，它们的配置语法分别如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">http://hostname:port?key=value</span><br><span class="line">https://hostname:port?key=value</span><br></pre></td></tr></table></figure></p>
<p>还需要添加activem1-optional包.<br>VI. 虚拟机协议（virtual machine protocol， VM）<br>ActiveMQ还可以嵌入Java应用程序中，这样Java程序与broker之间的连接不会经过网络，而是在同一个JVM中进行，从而可以减少网络传输，大幅提升性能。这种方式成为虚拟机协议。使用VM协议的broker拥有与其它协议相同的功能，VM connector的配置语法如下：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vm://brokerName?key=value</span><br></pre></td></tr></table></figure></p>
<p><a href="http://activemq.apache.org/vm-transport-reference.html" target="_blank" rel="noopener">VM connector详细介绍</a></p>
<p>######3). network connectors部署集群<br>I. 网络连接模式<br>针对海量消息所要求的横向扩展性和系统的高可用性，ActiveMQ提供了网络连接模式的集群功能。简单的说，就是通过把多个不同的broker实例连接在一起，作为一个整体对外提供服务，从而提高整体对外的消息服务能力。通过这种方式连接在一起的broker实例之间，可以共享队列和消费者列表，从而达到分布式队列的目的。<br>II. 拓扑结构<br>几种不同的ActiveMQ部署拓扑结构（嵌入、主从复制、网络连接）：<br><img src="https://upload-images.jianshu.io/upload_images/3110861-22dc6736335faa3e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图12.png"></p>
<p>III. 配置示例<br>在activemq.xml的broker节点内添加：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;networkConnectors&gt;</span><br><span class="line">      &lt;networkConnectoruri=“static:(tcp://localhost:62001)”/&gt;</span><br><span class="line">&lt;/networkConnectors&gt;</span><br></pre></td></tr></table></figure></p>
<p>uri也可以使用其他两种方式：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">multicast://default</span><br><span class="line">masterslave:(tcp://host1:61616,tcp://host2:61616,tcp://..)</span><br></pre></td></tr></table></figure></p>
<p>IV. 静态URI配置<br>使用静态URI方式可以指定多个URL，networkConnector将连接到每一个broker。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;networkConnectors&gt;</span><br><span class="line">    &lt;networkConnector uri=&quot;static:(tcp://host1:61616,tcp://host2:61616,tcp://..)&quot;/&gt;</span><br><span class="line">&lt;/networkConnectors&gt;</span><br></pre></td></tr></table></figure></p>
<p>URI的几个属性：</p>
<table>
<thead>
<tr>
<th>属性</th>
<th>默认值</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>initialReconnectDelay</td>
<td>1000</td>
<td>重连之前等待的时间(ms) (如果useExponentialBackOff为 false)</td>
<td></td>
</tr>
<tr>
<td>maxReconnectDelay</td>
<td>30000</td>
<td>重连之前等待的最大时间(ms)</td>
<td></td>
</tr>
<tr>
<td>useExponentialBackOff</td>
<td>true</td>
<td>每次重连失败时是否增大等待时间</td>
<td></td>
</tr>
<tr>
<td>backOffMultiplier</td>
<td>2</td>
<td>增大等待时间的系数</td>
<td></td>
</tr>
</tbody>
</table>
<p>####<a href="https://gitee.com/mazaiting/distributed" target="_blank" rel="noopener">代码下载</a></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/08/06/Distributed/分布式--ActiveMQ-消息中间件(一)/" rel="next" title="分布式--ActiveMQ-消息中间件(一)">
                <i class="fa fa-chevron-left"></i> 分布式--ActiveMQ-消息中间件(一)
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/08/06/Distributed/分布式--Dubbo-分布式服务/" rel="prev" title="分布式--Dubbo-分布式服务">
                分布式--Dubbo-分布式服务 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/blog/images/avatar.jpeg"
                alt="凌浩雨" />
            
              <p class="site-author-name" itemprop="name">凌浩雨</p>
              <p class="site-description motion-element" itemprop="description">专业从事于移动端开发，Android与iOS均有涉及，主做Android开发与React Native开发</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">393</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">凌浩雨</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
